/**
 * @IdentifierFactory.java  COPYRIGHT xiaojian
 * 
 * Created on 2018年3月16日 下午3:44:37
 */
package xiaojian.toolkit.util;

import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Preconditions;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;

/**
 * length(2byte) type(1byte)  value(xxbyte)
 * 长度至少超过三个字节。 length = 1 + value.length
 * 
 * @author <a href="mailto:cxj2000@gmail.com">xiaojian.cao</a>
 *
 */
public class IdentifierFactory {
	
	private static final Logger logger = LoggerFactory.getLogger(IdentifierFactory.class);

	private static BiMap<Byte, Class<?>> typeIdentifier = HashBiMap.create();
	
	static {
		typeIdentifier.put((byte)0x0, IntIdentifier.class);
		typeIdentifier.put((byte)0x1, UUIDIdentifier.class);
	}
	
	/**
	 * 从字节数组中生成一个标识。字节前面不需要带有长度信息。也就是type + value。
	 * 
	 * @param idByte 字节数组
	 * @return 
	 */
	public static Identifier<?> fromByte(byte[] idByte) throws UnsupportIdTypeException {
		Preconditions.checkArgument(idByte != null & idByte.length > 3);
		
		//byte[] length = ArrayUtils.subarray(idByte, 0, 2);
		byte idType = idByte[0];
		byte[] content = ArrayUtils.subarray(idByte, 1, idByte.length);
		
		Class<?> identifierClass = typeIdentifier.get(idType);
		if (identifierClass == null) {
			throw new UnsupportIdTypeException("Unsupport type[" + idType + "].");
		}
		
		Identifier<?> result = null;
		try {
			result = (Identifier<?>) identifierClass.newInstance();
		} catch (Exception e) {
			logger.debug("IdentifierFactory error.", e);
			return null;
		} 
		
		return result.fromByte(content);
	}
	
	/**
	 * 从一个Identifier对象生成字节流。带有长度信息，legth+type+value。
	 * 
	 * @param id
	 * @return
	 * @throws UnsupportIdTypeException
	 */
	public static byte[] gerIdByte(Identifier<?> id) throws UnsupportIdTypeException {
		Preconditions.checkArgument(id != null);
		
		Byte type = typeIdentifier.inverse().get(id.getClass());
		if (type == null) {
			throw new UnsupportIdTypeException("Unsupport type[" + id.getClass() + "].");
		}
		
		byte[] content = id.valueAsByte();
		int length = 1 + content.length;
		
		return ByteUtils.union(DefaultNumberCodecs.getBigEndianNumberCodec().int2Bytes(length, 2), new byte[]{type}, content);
	}
}
